package com.kin207.netty.udp;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.eventbus.EventBus;
import com.kin207.netty.context.RequestContext;
import com.kin207.netty.handle.IMessageHandle;
import com.kin207.netty.handle.IMessageHandleAdapter;
import com.kin207.netty.listener.IEventBusListener;
import com.kin207.netty.listener.eventbus.CreatedListenerEvent;
import com.kin207.netty.listener.eventbus.DestroyedListenerEvent;
import com.kin207.netty.msg.IMessageParse;
import com.kin207.netty.server.IServer;
import com.kin207.netty.session.Session;
import com.kin207.netty.session.SessionManager;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;

public class UdpChannelInboundHandler extends SimpleChannelInboundHandler<DatagramPacket> implements IEventBusListener<IMessageHandle>{
	final static Logger logger = LoggerFactory.getLogger(UdpChannelInboundHandler.class);
	
	private ChannelHandlerContext channelHandlerContext;
	private EventBus eventBus;
	private IServer server;
	
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		super.channelActive(ctx);
		logger.debug("channel active, address:{}", ctx.channel().remoteAddress());
		channelHandlerContext = ctx;
	}
	
	public void callRead(ChannelHandlerContext ctx, DatagramPacket datagramPacket) throws Exception{
		channelRead0(ctx, datagramPacket);
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx1, DatagramPacket datagramPacket) throws Exception {
		Session session = server.getSessionManager().addSession(datagramPacket.sender(), ctx1);
		ChannelHandlerContext ctx = session.getChannelHandlerContext();
		SessionManager sessionManager = server.getSessionManager();
		
		String msg = datagramPacket.content().toString(CharsetUtil.UTF_8);
		logger.debug("channel read, message:{}", msg);
		IMessageHandle handle = server.getMessageHandleAdapter().adapter(msg);
		if(handle==null){
			logger.error("not handle, address:{}, message:{}", ctx.channel().remoteAddress(), msg);
			sessionManager.sendMessage(ctx, "error:404",System.currentTimeMillis());
			return;
		}
		RequestContext req = new RequestContext(this.server, ctx, msg);
		RequestContext.curr.set(req);
		try {
			Object param = server.getMessageParse().parse(msg, handle.paramClass());
			req.setParams(param);
			postCreatedEvent(handle);
			handle.handle(param);
			postDestroyedEvent(handle);
		} catch (Exception e) {
			logger.error("handle error, address:{}, msg:{}, handle:{} ", ctx.channel().remoteAddress(), msg, handle, e);
			sessionManager.sendMessage(ctx, "error:"+e.getMessage(),System.currentTimeMillis());
		}finally{
			RequestContext.curr.remove();
		}
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		logger.error("exception caught, address:{}", ctx.channel().remoteAddress(), cause);
	}

	public ChannelHandlerContext getChannelHandlerContext() {
		return channelHandlerContext;
	}

	public EventBus getEventBus() {
		return eventBus;
	}

	public void setEventBus(EventBus eventBus) {
		this.eventBus = eventBus;
	}
	public void postCreatedEvent(IMessageHandle o) {
		if(getEventBus()!=null){
			getEventBus().post(new CreatedListenerEvent<IMessageHandle>(o));
		}
	}

	public void postDestroyedEvent(IMessageHandle o) {
		if(getEventBus()!=null){
			getEventBus().post(new DestroyedListenerEvent<IMessageHandle>(o));
		}
	}

	public IServer getServer() {
		return server;
	}

	public void setServer(IServer server) {
		this.server = server;
	}
	
	
}
